package contrl

import (
	"core/utils"
	"fmt"
	"strconv"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/go-xorm/builder"
)

type (
	Error struct {
		StatusCode int
		ErrCode    int
		ErrInfo    string
	}

	Response struct {
		Data    interface{} `json:"data"`
		ErrCode int         `json:"err_code"`
		ErrInfo string      `json:"err_info"`
	}

	Sign struct {
		Uid       int64
		ExpiredAt time.Time
	}

	Fields []string
)

func GenError(err error) (e Error) {
	utils.StackLog(err.Error())
	e = Error{
		StatusCode: 200,
		ErrCode:    50000,
		ErrInfo:    err.Error(),
	}
	return
}

func GenErrorMsg(msg string) (e Error) {
	utils.StackLog(msg)
	e = Error{
		StatusCode: 200,
		ErrCode:    40002,
		ErrInfo:    msg,
	}
	return
}

func ParseInt(c *gin.Context, key string, val *int, cols *Fields) {
	out := GetInt(c, key)
	if out <= 0 {
	}
	*val = out
	*cols = append(*cols, key)
	return
}

func ParseString(c *gin.Context, key string, val *string, cols *Fields) {
	out := GetString(c, key)
	if out == "" {
		return
	}
	*val = out
	*cols = append(*cols, key)
	return
}

func ParseInt64(c *gin.Context, key string, val *int64, cols *Fields) {
	out := GetInt64(c, key)
	if out <= 0 {
		return
	}
	*val = out
	*cols = append(*cols, key)
	return
}

func ParseFloat64(c *gin.Context, key string, val *float64, cols *Fields) {
	out := GetFloat64(c, key)
	if out <= 0 {
		return
	}
	*val = out
	*cols = append(*cols, key)
	return
}

func ParseBool(c *gin.Context, key string, val *bool, cols *Fields) {
	v := GetString(c, key)
	if v == "null" {
		return
	}
	out, _ := strconv.ParseBool(v)
	*val = out
	*cols = append(*cols, key)
	return
}

func GetTime(c *gin.Context, key string) time.Time {
	unixTime := GetInt64(c, key)
	if unixTime > 10000000000 {
		unixTime /= 1000
	}
	if unixTime == 0 {
		return time.Time{}
	}
	return time.Unix(unixTime, 0)
}

func GetSlice(c *gin.Context, key string) (values []string) {
	values = make([]string, 0)
	i := 0
	for {
		v, exist := c.Request.Form[fmt.Sprintf("%s[%d]", key, i)]
		if !exist {
			break
		}
		values = append(values, v[0])
		i++
	}
	return
}

func GetInt(c *gin.Context, key string) (out int) {
	out, _ = strconv.Atoi(c.GetString(key))
	return
}

func GetString(c *gin.Context, key string) (out string) {
	return c.GetString(key)
}

func GetInt64(c *gin.Context, key string) (out int64) {
	out, _ = strconv.ParseInt(c.GetString(key), 10, 64)
	return
}

func GetFloat64(c *gin.Context, key string) (out float64) {
	out, _ = strconv.ParseFloat(c.GetString(key), 64)
	return
}

func GetBool(c *gin.Context, key string) (out bool) {
	out, _ = strconv.ParseBool(c.GetString(key))
	return
}

func GetSign(c *gin.Context) (sign *Sign) {
	sign = new(Sign)
	value, exists := c.Get("_sign")
	if !exists {
		return
	}
	sign, _ = value.(*Sign)
	return
}

func GetUID(c *gin.Context) (uid int64) {
	sign := new(Sign)
	value, exists := c.Get("_sign")
	if !exists {
		return
	}
	sign, _ = value.(*Sign)
	uid = sign.Uid
	return
}

type Cond struct {
	Cond    builder.Cond
	Context *gin.Context
}

func NewCommonCond(c *gin.Context) (cond *Cond) {
	return &Cond{
		Cond:    builder.NewCond(),
		Context: c,
	}
}

func (cond *Cond) Eq(key string) *Cond {
	if val := cond.Context.GetString(key); val != "" {
		cond.Cond = cond.Cond.And(builder.Eq{key: val})
	}
	return cond
}

func (cond *Cond) Like(key string) *Cond {
	if val := cond.Context.GetString(key); val != "" {
		cond.Cond = cond.Cond.And(builder.Like{key, val})
	}
	return cond
}

func (cond *Cond) Neq(key string, values interface{}) *Cond {
	cond.Cond = cond.Cond.And(builder.Neq{key: values})
	return cond
}

func (cond *Cond) In(key string, values interface{}) *Cond {
	cond.Cond = cond.Cond.And(builder.In(key, values))
	return cond
}
